﻿using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Common.UnitTests;
using Moq;
using NUnit.Framework;
using Wombat.Core;
using Wombat.Core.Diagnostics;
using Wombat.Core.Gates;
using Wombat.Core.Services;

namespace Core.UnitTests.Gates
{
    public class ServiceEndpointBaseGateUnitTests: UnitTestBase
    {
        #region Types

        private class TestServiceGate : ServiceEndpointBaseGate
        {
            public TestServiceGate(IObservationManager observationManager, IConfigurationService configurationService, IDiagnosticsService diagnosticsService) : base(observationManager, configurationService, diagnosticsService)
            {
            }

            public void Send(ITagValue value)
            {
                base.SendMessage(value);
            }

            public void ThrowError()
            {
                throw new NotImplementedException();
            }

            public override Task StartAsync()
            {
                throw new NotImplementedException();
            }

            public override Task StopAsync()
            {
                throw new NotImplementedException();
            }

            protected override void DisposeService()
            {
                throw new NotImplementedException();
            }
        }

        #endregion


        [Test]
        public void CanSubscribeToEverything()
        {
            var service = GetTestService();
            var observer = new Mock<IObserver<ITagValue>>();
            service.Subscribe(null, observer.Object);
            observer.Setup(o => o.OnNext(It.IsAny<ITagValue>()))
                .Verifiable();

            service.Send(new Mock<ITagValue>().Object);
            observer.VerifyAll();
        }

        [Test]
        public void CanSubscribeToPattern()
        {
            //Note: Pattern test should be in its own place
            var actuals = new List<ITagValue>();
            var service = GetTestService();
            var observer = new Mock<IObserver<ITagValue>>();
            service.Subscribe(GetEveythingPattern(), observer.Object);
            observer.Setup(o => o.OnNext(It.IsAny<ITagValue>()))
                .Callback<ITagValue>(actuals.Add);

            var expected = new[]
                               {
                                   GetTestTagValue("j", 1),
                                   GetTestTagValue("2", 2),
                                   GetTestTagValue("3", 3)
                               };

            Assert.That(expected, Is.EquivalentTo(actuals));
        }

        [Test]
        public void ErrorHappened()
        {
            var service = GetTestService();
            var errorObserver = new Mock<IObserver<IDiagnosticsMessage>>();
            service.SubscribeDiagnostics(DiagnosticsLevel.Error, errorObserver.Object);
            errorObserver.Setup(e => e.OnNext(It.IsAny<IDiagnosticsMessage>()))
                .Verifiable();

            service.ThrowError();
            errorObserver.VerifyAll();
        }

        #region Private Methods

        private static ITagValue GetTestTagValue(string name, int val)
        {
            var tag = new Mock<ITag>();
            tag.Setup(t => t.Name).Returns(name);
            var v = new Mock<ITagValue<int>>();
            v.Setup(t => t.TagId).Returns(Guid.NewGuid);
            v.Setup(t => t.Value).Returns(val);
            return v.Object;
        }

        private static string GetEveythingPattern()
        {
            return "*";
        }

        private static TestServiceGate GetTestService()
        {
            return new TestServiceGate(null, null, null);
        }

        #endregion

    }
}
